﻿
// <copyright file="MetricsEnabledRequestHandlerDecorator.cs" company="Subhadra Software Solutions">
//   
// </copyright>
// <summary>
//   The metrics enabled request handler decorator.
// </summary>

namespace SubhadraSolutions.Sharp.Utils.RequestProcessing
{
    using System;

    using SubhadraSolutions.Sharp.Utils.Diagnostics;

    /// <summary>
    /// The metrics enabled request handler decorator.
    /// </summary>
    /// <typeparam name="TRequest">
    /// The type of the request.
    /// </typeparam>
    public class MetricsEnabledRequestHandlerDecorator<TRequest> : AbstractRequestHandler<TRequest>, IMetricsEnabledRequestHandler<TRequest>
        where TRequest : IRequest
    {
        #region Fields

        /// <summary>
        ///     The decoratedRequestHandler
        /// </summary>
        private readonly IRequestHandler<TRequest> decoratedRequestHandler;

        /// <summary>
        ///     The metrics
        /// </summary>
        private readonly RequestHandlerMetrics metrics;

        #endregion Fields

        #region Constructors and Finalizers

        /// <summary>
        /// Initializes a new instance of the <see cref="MetricsEnabledRequestHandlerDecorator{TRequest}"/> class.
        /// </summary>
        /// <param name="decoratedRequestHandler">
        /// The decoratedRequestHandler.
        /// </param>
        public MetricsEnabledRequestHandlerDecorator(IRequestHandler<TRequest> decoratedRequestHandler)
        {
            this.decoratedRequestHandler = decoratedRequestHandler;
            this.metrics = new RequestHandlerMetrics();
        }

        #endregion Constructors and Finalizers

        #region Public Methods and Operators

        /// <summary>
        ///     The get metrics.
        /// </summary>
        /// <returns>
        ///     The <see cref="RequestHandlerMetrics" />.
        /// </returns>
        public RequestHandlerMetrics GetMetrics()
        {
            return this.metrics.Clone() as RequestHandlerMetrics;
        }

        #endregion Public Methods and Operators

        #region Methods

        /// <summary>
        /// The dispose.
        /// </summary>
        /// <param name="disposing">
        /// The disposing.
        /// </param>
        protected override void Dispose(bool disposing)
        {
        }

        /// <summary>
        /// The initialize protected.
        /// </summary>
        protected override void InitializeProtected()
        {
        }

        /// <summary>
        /// The process request protected.
        /// </summary>
        /// <param name="request">
        /// The request.
        /// </param>
        /// <returns>
        /// The <see cref="IResponse"/>.
        /// </returns>
        protected override IResponse processRequestProtected(TRequest request)
        {
            this.metrics.RequestReceived();
            long ticksBefore = SharedStopWatch.ElapsedTicks;
            IResponse response = null;
            try
            {
                response = this.decoratedRequestHandler.ProcessRequest(request);
            }
            finally
            {
                long ticksTaken = SharedStopWatch.ElapsedTicks - ticksBefore;
                this.metrics.RequestProcessed(ticksTaken, response == null || response.Result == ProcessingResult.Fail);
                if (response != null)
                {
                    var metricsEnabledResponse = response as IMetricsEnabledResponse;
                    if (metricsEnabledResponse != null)
                    {
                        metricsEnabledResponse.TimeTaken = TimeSpan.FromTicks(ticksTaken);
                    }
                }
            }

            return response;
        }

        #endregion Methods
    }
}